package atom.core3.hibernate.util;

import java.util.ArrayList;
import java.util.List;

public class HQLComposer {

	public static final String DOT = ".";

	public static final String WILDCARD = "*";

	public static final String SELECT = "SELECT";

	public static final String FROM = "FROM";

	public static final String WHERE = "WHERE";

	public static final String INSERT = "INSERT INTO";

	public static final String VALUES = "VALUES";

	public static final String UPDATE = "UPDATE";

	public static final String DELETE = "DELETE";

	public static final String SET = "SET";

	public static final String SPACE = " ";

	public static final String COMMA = ",";

	public static final String LEFT_PARENTHESES = "(";

	public static final String RIGHT_PARENTHESES = ")";

	public static final String QUESTION_MARK = "?";

	public static final String EQUAL = "=";

	public static final String GREAT_EQUAL = ">=";

	public static final String LESS_EQUAL = "<=";

	public static final String IN = "IN";

	public static final String AND = "AND";

	public static final String SINGLE_QUOTATION = "'";

	private static final String ORDER_BY = "ORDER BY";

	private static final Object DESC = "DESC";

	/**
	 * 检查字符串是不是空或者空字符串。
	 *
	 * @param string
	 *           要检查的字符串
	 * @return 字符串为空或空字符串返回真。
	 */
	public static boolean isEmpty(final String string) {
		return (string == null || string.length() == 0);
	}

	private final StringBuffer hql;

	private final List<StringBuffer> values = new ArrayList<StringBuffer>();

	private final List<StringBuffer> conditions = new ArrayList<StringBuffer>();

	private StringBuffer pre;

	private final String shortName;

	private StringBuffer post;

	/**
	 * 初始化成员。<br>
	 * 指定要操作的对象（表）及其别名。
	 *
	 * @param entityClass
	 *           实体类(HQL里面是类名)
	 * @param shortName
	 *           HQL里使用的表的别名。
	 */
	public HQLComposer(final Class<?> entityClass, final String shortName) {
		this.shortName = shortName;
		this.hql = new StringBuffer();
		this.hql.append(FROM);
		this.hql.append(SPACE);
		this.hql.append(entityClass.getName());
		this.hql.append(SPACE);
		this.hql.append(this.shortName);
		this.hql.append(SPACE);
	}

	/**
	 * 如果参数不为空（{@link HQLComposer#isEmpty(String)}）。为HQL添加一个查询条件。指定字段的值应该与参数相等。
	 *
	 * @param columnName
	 *           字段
	 * @param parameter
	 *           参数
	 */
	public void addCondition(final String columnName, final String parameter) {
		addCondition(columnName, parameter, EQUAL);
	}

	/**
	 * 如果参数不为空（{@link HQLComposer#isEmpty(String)}）。为HQL添加一个查询条件。
	 *
	 * @param columnName
	 *           字段
	 * @param parameter
	 *           参数
	 * @param relation
	 *           关系运算符 例如：EQUAL GREAT_EQUAL LESS_EQUAL
	 */
	public void addCondition(final String columnName, final String parameter, final String relation) {
		if (!isEmpty(parameter)) {
			StringBuffer condition = new StringBuffer();
			condition.append(this.shortName);
			condition.append(DOT);
			condition.append(columnName);
			condition.append(relation);
			condition.append(SINGLE_QUOTATION);
			condition.append(parameter);
			condition.append(SINGLE_QUOTATION);
			condition.append(SPACE);
			this.conditions.add(condition);
		}
	}

	/**
	 * 如果参数不为空（见 {@link HQLComposer#isEmpty(String)}）。为HQL添加一个更新字段。
	 *
	 * @param columnName
	 *           字段
	 * @param parameter
	 *           参数
	 */
	public void addValue(final String columnName, final String parameter) {
		if (!isEmpty(parameter)) {
			StringBuffer condition = new StringBuffer();
			condition.append(this.shortName);
			condition.append(DOT);
			condition.append(columnName);
			condition.append(EQUAL);
			condition.append(SINGLE_QUOTATION);
			condition.append(parameter);
			condition.append(SINGLE_QUOTATION);
			condition.append(SPACE);
			this.values.add(condition);
		}
	}

	/**
	 * <ol>
	 * <li>如果条件不为空，在查询语句后面附加一个 WHERE 并把条件附加到其后。</li>
	 * <li>如果操作符不为空，在语句前面附加此操作符。</li>
	 * <li>如果后置语句不为空，在语句后面附加后置语句。</li>
	 * </ol>
	 *
	 * @return 根据先前指定的条件生成的HQL。
	 */
	public String getHQLString() {
		if (this.pre == null) {
			return getQueryHQL().toString();
		}
		int size = this.values.size();
		if (size > 0) {
			this.hql.append(SET);
			this.hql.append(SPACE);
			while (size-- > 1) {
				this.hql.append(this.values.get(size));
				this.hql.append(COMMA);
				this.hql.append(SPACE);
			}
			this.hql.append(this.values.get(size));
		}
		this.pre.append(getQueryHQL());
		return this.pre.toString();
	}


	private StringBuffer getQueryHQL() {
		int size = this.conditions.size();
		if (size > 0) {
			this.hql.append(WHERE);
			this.hql.append(SPACE);
			while (size-- > 1) {
				this.hql.append(this.conditions.get(size));
				this.hql.append(AND);
				this.hql.append(SPACE);
			}
			this.hql.append(this.conditions.get(size));
		}
		if (this.post != null) {
			this.hql.append(this.post);
		}
		return this.hql;
	}

	/**
	 * @param columnName
	 *           字段
	 * @param parameter
	 *           参数
	 */
	protected void addCondition(final String columnName, final String[] parameter) {
		if (parameter != null && parameter.length > 0) {
			StringBuffer condition = new StringBuffer();
			condition.append(this.shortName);
			condition.append(DOT);
			condition.append(columnName);
			condition.append(SPACE);
			condition.append(IN);
			condition.append(SPACE);
			condition.append(LEFT_PARENTHESES);
			condition.append(SPACE);
			int i = parameter.length;
			while (i-- > 1) {
				condition.append(SINGLE_QUOTATION);
				condition.append(parameter[i]);
				condition.append(SINGLE_QUOTATION);
				condition.append(COMMA);
				condition.append(SPACE);
			}
			condition.append(SINGLE_QUOTATION);
			condition.append(parameter[i]);
			condition.append(SINGLE_QUOTATION);
			condition.append(RIGHT_PARENTHESES);
			condition.append(SPACE);
			this.conditions.add(condition);
		}
	}

	/**
	 * 为HQL添加前置操作符。<br/>
	 * 例如：DELETE
	 *
	 * @param string
	 *           操作符
	 */
	protected void addManipulation(final String string) {
		this.pre = new StringBuffer(string);
		this.pre.append(SPACE);
	}

	/**
	 * 为HQL添加后置order by语句，默认为正序排列。
	 *
	 * @param columnName
	 *           要排序的字段
	 */
	protected void orderBy(final String columnName) {
		orderBy(columnName, false);
	}

	/**
	 * 为HQL添加后置order by语句
	 *
	 * @param columnName
	 *           要排序的字段
	 * @param desc
	 *           逆序标志
	 */
	protected void orderBy(final String columnName, final boolean desc) {
		this.post = new StringBuffer(ORDER_BY);
		this.post.append(SPACE);
		this.post.append(columnName);
		if (desc) {
			this.post.append(SPACE);
			this.post.append(DESC);
		}
	}

}
